package com.yuba.front.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuba.common.core.constant.Constants;
import com.yuba.common.core.constant.UserConstants;
import com.yuba.common.core.exception.front.FishSiteException;
import com.yuba.common.core.utils.MapstructUtils;
import com.yuba.common.core.utils.SpringUtils;
import com.yuba.common.core.utils.StringUtils;
import com.yuba.common.core.utils.ValidatorUtils;
import com.yuba.common.core.validate.AddGroup;
import com.yuba.common.mybatis.core.page.PageQuery;
import com.yuba.common.mybatis.core.page.TableDataInfo;
import com.yuba.common.satoken.utils.LoginHelper;
import com.yuba.front.domain.CollectFishSite;
import com.yuba.front.domain.FishSite;
import com.yuba.front.domain.FishSiteComments;
import com.yuba.front.domain.bo.FishSiteBo;
import com.yuba.front.domain.param.FishSiteParam;
import com.yuba.front.domain.vo.FishSiteDetailVo;
import com.yuba.front.domain.vo.FishSiteVo;
import com.yuba.front.event.GetUserInfoEvent;
import com.yuba.front.mapper.CollectFishSiteMapper;
import com.yuba.front.mapper.FishSiteCommentsMapper;
import com.yuba.front.mapper.FishSiteMapper;
import com.yuba.front.mapper.FishSiteRatingsMapper;
import com.yuba.front.service.IFishSiteService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 钓场Service业务层处理
 *
 * @author modakai
 * @date 2024-12-11
 */
@RequiredArgsConstructor
@Service
public class FishSiteServiceImpl implements IFishSiteService {

    private final FishSiteMapper baseMapper;
    private final CollectFishSiteMapper collectFishSiteMapper;
    private final FishSiteCommentsMapper fishSiteCommentsMapper;
    private final FishSiteRatingsMapper ratingsMapper;

    /**
     * 查询钓场
     *
     * @param fishSiteId 主键
     * @return 钓场
     */
    @Override
    public FishSiteVo queryById(Long fishSiteId) {
        return baseMapper.selectVoById(fishSiteId);
    }

    /**
     * 分页查询钓场列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 钓场分页列表
     */
    @Override
    public TableDataInfo<FishSiteVo> queryPageList(FishSiteBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<FishSite> lqw = buildQueryWrapper(bo);
        Page<FishSiteVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的钓场列表
     *
     * @param bo 查询条件
     * @return 钓场列表
     */
    @Override
    public List<FishSiteVo> queryList(FishSiteBo bo) {
        LambdaQueryWrapper<FishSite> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<FishSite> buildQueryWrapper(FishSiteBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<FishSite> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), FishSite::getName, bo.getName());
        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), FishSite::getAddress, bo.getAddress());
        lqw.eq(StringUtils.isNotBlank(bo.getProvince()), FishSite::getProvince, bo.getProvince());
        lqw.eq(StringUtils.isNotBlank(bo.getCity()), FishSite::getCity, bo.getCity());
        lqw.eq(bo.getLatitude() != null, FishSite::getLatitude, bo.getLatitude());
        lqw.eq(bo.getLongitude() != null, FishSite::getLongitude, bo.getLongitude());
        lqw.eq(StringUtils.isNotBlank(bo.getFeeType()), FishSite::getFeeType, bo.getFeeType());
        lqw.eq(bo.getAmount() != null, FishSite::getAmount, bo.getAmount());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), FishSite::getDescription, bo.getDescription());
        lqw.eq(StringUtils.isNotBlank(bo.getImageUrl()), FishSite::getImageUrl, bo.getImageUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getPublicFlag()), FishSite::getPublicFlag, bo.getPublicFlag());
        lqw.eq(bo.getUserId() != null, FishSite::getUserId, bo.getUserId());
        return lqw;
    }

    /**
     * 新增钓场
     *
     * @param bo 钓场
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(FishSiteBo bo) {
        FishSite add = MapstructUtils.convert(bo, FishSite.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setFishSiteId(add.getFishSiteId());
        }
        return flag;
    }

    /**
     * 修改钓场
     *
     * @param bo 钓场
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(FishSiteBo bo) {
        FishSite update = MapstructUtils.convert(bo, FishSite.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(FishSite entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除钓场信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 保存钓场
     *
     * @param body   钓场数据
     * @param userId 用户id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(FishSiteBo body, Long userId) {
        // 1. 判断，如果是收费类型，需要指定收费金额
        if (UserConstants.YES.equals(body.getFeeType()) && body.getAmount() == null) {
            throw new FishSiteException("front.fish.site.save.amount.required");
        }
        // 2. 校验数据
        body.setUserId(userId);

        ValidatorUtils.validate(body, AddGroup.class);

        // 3. 保存钓场
        Boolean inserted = insertByBo(body);
        if (!inserted) {
            throw new FishSiteException("front.fish.site.save.fail");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyPublic(Long fishSiteId, String publicFlag, Long userId) {

        // 校验类型
        if (!UserConstants.YES.equals(publicFlag) && !Constants.NO.equals(publicFlag)) {
            throw new FishSiteException("front.fish.site.modify.public.fail");
        }
        // 更新数据
        FishSite fishSite = new FishSite();
        fishSite.setPublicFlag(publicFlag);
        int update = baseMapper.update(
            fishSite,
            new LambdaQueryWrapper<FishSite>().eq(FishSite::getFishSiteId, fishSiteId).eq(FishSite::getUserId, userId));
        if (update <= 0) {
            throw new FishSiteException("front.fish.site.modify.public.fail");
        }
    }

    /**
     * @param body      查询条件
     * @param pageQuery 分页条件
     * @return 钓场列表
     */
    @Override
    public TableDataInfo<FishSiteVo> customerPageList(FishSiteParam body, PageQuery pageQuery) {
        // 判断参数
        String feeType = body.getFeeType();
        if (UserConstants.YES.equals(feeType)) {
            Long startAmount = body.getStartAmount();
            Long endAmount = body.getEndAmount();
            if (startAmount != null && endAmount == null) {
                body.setEndAmount(startAmount);
                body.setStartAmount(0L);
            } else if (startAmount == null && endAmount != null) {
                body.setStartAmount(0L);
            }
        }
        // 1. 构建分页条件
        Page<FishSiteVo> page = baseMapper.customerPageList(pageQuery.build(), body);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<FishSiteVo> queryPageListUserCollectFishSite(PageQuery pageQuery, Long userId) {
        // 查询
        Page<FishSiteVo> page = baseMapper.queryPageListUserCollectFishSite(pageQuery.build(), userId);
        return TableDataInfo.build(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> ids, Long userId) {
        baseMapper.deleteByKey(ids, userId);
        // 2 删除评论
        LambdaQueryWrapper<FishSiteComments> fishSiteCommentsLqw = new LambdaQueryWrapper<FishSiteComments>()
            .in(FishSiteComments::getFishSiteId, ids);
        fishSiteCommentsMapper.delete(fishSiteCommentsLqw);
        // 3 删除评分
        ratingsMapper.deleteByKeys(ids);
        // 4 删除收藏
        LambdaQueryWrapper<CollectFishSite> collectLqw = new LambdaQueryWrapper<CollectFishSite>()
            .in(CollectFishSite::getFishSiteId, ids).eq(CollectFishSite::getUserId, userId);
        int delete = collectFishSiteMapper.delete(collectLqw);
        if (delete != ids.size()) {
            throw new FishSiteException("front.delete.error");
        }
    }

    @Override
    public List<FishSiteVo> hot() {
        return baseMapper.selectHot();
    }

    @Override
    public List<String> searchOptions(String type) {
        if ("province".equalsIgnoreCase(type)) {
            return baseMapper.selectProvince();
        }

        return baseMapper.selectCity();
    }

    @Override
    public FishSiteDetailVo getPublicDetail(Long fishSiteId) {
        FishSiteDetailVo fishSiteDetailVo = baseMapper.selectVoDetail(fishSiteId);
        if (fishSiteDetailVo == null) {
            throw new FishSiteException("front.fish.site.not.exist");
        }
        // 获取发布者用户的信息
        GetUserInfoEvent event = GetUserInfoEvent.builder().userId(fishSiteDetailVo.getUserId()).build();
        SpringUtils.context().publishEvent(event);
        fishSiteDetailVo.setNickname(event.getUserVo().getNickname());
        fishSiteDetailVo.setAvatar(event.getUserVo().getAvatar());

        // 判断是否该用户已收藏
        Long userId = LoginHelper.getUserId();
        LambdaQueryWrapper<CollectFishSite> collectLqw = new LambdaQueryWrapper<CollectFishSite>()
            .eq(CollectFishSite::getFishSiteId, fishSiteId);
        Long collectCount = collectFishSiteMapper.selectCount(collectLqw);
        collectLqw.eq(CollectFishSite::getUserId, userId);
        CollectFishSite collectFishSite = collectFishSiteMapper.selectOne(collectLqw);

        fishSiteDetailVo.setCollectFlag(!ObjectUtils.isEmpty(collectFishSite));
        fishSiteDetailVo.setCollectCount(collectCount);

        return fishSiteDetailVo;
    }
}
